/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lintulaskenta.tipuapiValidointi;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import lintulaskenta.tipuapiValidointi.Document.Node;
import lintulaskenta.entity.*;
import lintulaskenta.validointi.validointiKirjasto;
import org.apache.http.client.methods.HttpPost;

/**
 *
 * @author jukkapajunen, jjnyman
 */
public class TipuApiValidator {

    private String kunta;
    public TipuAPIClient api = null;
    public TipuApiResource lintulajit = null;
    public TipuApiResource kunnat = null;
    public TipuApiResource havainnoijat = null;
    public TipuApiResource synonyymit = null;
    public TipuApiResource koodit = null;
    public HttpClientService kokoAPI = null;
    //tipun yhteyttä varten muuttujia
    private String[] salasanat;
    private BufferedReader buffreader;
    private validointiKirjasto validointikirjasto;

    public TipuApiValidator() throws FileNotFoundException, IOException {
        pohjustaResurssit();
    }

    /*
     * Luodaan yhteys tipuAPIin ja noudetaan tarvittavat resurssit (lintulajit etc)
     * Lopuksi yhteys suljetaan
     */
    /*
     * Luokaa omaan kansioon tiedosto, jossa ensimmäisellä rivillä url, tokalla käyttäjätunnus ja kolmannella passu.
     * Ei sitten vahingossa mene googleen tipun passuja, vaan korkeintaan teidän kotihakemiston polku.
     * Jotain ongelmia ilmennyt laitoksenkin koneiden kanssa että tiedoston luku failaa ja tulee /HR-tagin puuttumisesta
     * virheilmoa. Jotain häikkää tässä tapauksessa salasanafilun lukemisessa. Merkistön tulisi olla UTF-8 ja rivinvaihdomerkin
     * UNIX.
     */
    private void salasanat() throws FileNotFoundException, IOException {
        salasanat = new String[3];
        FileInputStream file = new FileInputStream("/home/anna/NetBeansProjects/trunk/Linnutrokkaa/src/java/lintulaskenta/testi/tipuapi.txt");
        DataInputStream in = new DataInputStream(file);
        buffreader = new BufferedReader(new InputStreamReader(in));
        salasanat[0] = buffreader.readLine().trim();
        salasanat[1] = buffreader.readLine().trim();
        salasanat[2] = buffreader.readLine().trim();
    }

    private void pohjustaResurssit() throws FileNotFoundException, IOException {
        salasanat();
        try {
            api = new TipuAPIClient(salasanat[0], salasanat[1], salasanat[2]); // korjaa salasanat yms.
            kunnat = api.get(TipuAPIClientInterface.MUNICIPALITIES);
             lintulajit = api.get(TipuAPIClientInterface.SPECIES);
            koodit = api.get(TipuAPIClientInterface.CODES);
            havainnoijat = api.get(TipuAPIClientInterface.RINGERS);
            synonyymit = api.get(TipuAPIClientInterface.OBSERVER_SYNONYMS);
            kokoAPI = new HttpClientService(salasanat[0], salasanat[1], salasanat[2]);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (api != null) {
                api.close();
            }
        }
    }

    public HttpClientService getKokoAPI() {
        return kokoAPI;
    }

    public TipuApiResource getKoodit() {
        return koodit;
    }

    public void sulje() {
        kokoAPI.close();
    }


    /*
     * Palauttaa true, jos tipuAPI:sta löytyy kuusimerkkisellä lintukoodilla matchi
     * else false
     */
    public boolean tarkistaLintulaji(String lintu) {
        Node haettavaLintu = lintulajit.getById(lintu);
        if (haettavaLintu != null && lintu.length() == 6) {
            //System.out.println(haettavaLintu);
            return true;
        }
        return false;
    }

    /*
     * Maksimiarvo parven koolle on pistedatassa kaksinumeroinen, joten 99 siisi suurin. Oletettavasti yhden yksilön parvi ei ole parvi.
     */
    private boolean tarkistaParvenKoko(int parvenKoko) {
        if (parvenKoko < 100 && parvenKoko > 1) {
            return true;
        } else {
            return false;
        }
    }

    /*
     * Palauttaa true, jos tipuAPI:sta löytyy MAKSIMISSAAN kuusimerkkisellä kuntakoodilla matchi
     * else false
     */
    public boolean tarkistaKunta(String kunta) {
        Node haettavaKunta = kunnat.getById(kunta);
        if (haettavaKunta != null && kunta.length() <= 6) {
            //System.out.println(haettavaKunta);
            return true;
        } else {
            return false;
        }
    }

    public boolean tarkistaHavainnoijanumero(int numero) {
        if (numero > 0 && numero < 10000) {
            //System.out.println(haettavaKunta);
            return true;
        } else {
            return false;
        }
    }

    public boolean tarkistaRivinJuoksevanumero(int numero) {
        if (numero > 0 && numero < 33) {          // onko riittävän iso?? Ei välttis ja hajautetaan varmaan sinne pulauttimen omaan validointiin --Nyman
            return true;
        } else {
            System.out.println("Rivin juokesevanumero (" + numero + ") ei ole validi.");
        }
        return false;
    }

    public boolean tarkistaPisteidenLkm(int pisteidenLkm) {
        if (pisteidenLkm == 20) {                      // Mietittävä vielä pullauttimen puolella
            //System.out.println(ReitinNumerot);
            return true;
        } else {
            System.out.println("Huom! Reitillä on " + pisteidenLkm + " pistettä!!");
        }
        return false;
    }
    /*
     * Aika turha testi tällaisenaan
     */

    public boolean tarkistaLahempiPaikka(String lahempiPaikka) {
        if (lahempiPaikka.length() > 0 && lahempiPaikka.length() < 18) {  // tarkistaLahempiPaikka joka on max. 17 kirjainta
            //System.out.println(ReitinNumerot);
            return true;
        } else {
            return false;
        }
    }

    /*
     * Annetaan parametreinä perättäisdatasta kunnan lyhenne, latitudeksi sarakkeet 15-17(NNN) ja longitudeksi sarakkeet 18 & 19
     * Toistaiseksi täytyy ottaa tietokantayhteys jokaisen haun yhteydessä, luultavasti aika raskas operaatio.
     */
    public boolean tarkistapeninkulmaruutu(String kunta, int lati, int longi) throws IOException {
        HttpPost request = new HttpPost("https://h92.it.helsinki.fi/tipu-api/coordinate-validation-service?municipality=" + kunta.trim() + "&lat=" + lati + "0000&lon=" + longi + "0000&type=UNIFORM");
        String tuloste = kokoAPI.contentAsString(request);
        if (tuloste.contains("true")) {
            return true;
        } else {
            System.out.println("Kunta ja koordinaatit eivät matchaa: " + kunta + ":  P:" + lati + "  I:" + longi + "\n" + tuloste);
        }
        return false;
    }

    public boolean tarkistaReittiOlio(Reitti tarkistettava) throws IOException, Exception {
        boolean eiOleVirheita = true; // jos kaikki testit oikein, palautetaan true
        boolean onkoKuntaOikein = true;

        for (Havainnointitapahtuma h : tarkistettava.getHavainnointitapahtumat()) {
            kunta = h.getLaskentakunta().trim();

            if (tarkistaLahempiPaikka(h.getLahempiPaikka()) == false) {
                eiOleVirheita = false;
                System.out.println("Lähempipaikka sisältää liikaa tai liian vähän merkkejä: " + h.getLahempiPaikka());
            }


//            if (validointiKirjasto.kaykoLaskentaAika(tarkistettava, h) == false) {
//                eiOleVirheita = false;
//                System.out.println("Reitin laskenta-ajoissa on heittoa");//: \nTunnit: " +h.getAlkuTunnit() + "\nminuutit: " + h.getAlkuMinuutit());
//            }
//            if (validointiKirjasto.kaykoLaskentaPvm(tarkistettava, h) == false) {
//                System.out.println("Reitin laskentapäivämäärissä on heittoa");//: \nVuosi: " + h.getVuosi() + "\nKuukausi: " +h.getKuukausi() + "\nPäivä: " + h.getPaiva());
//                eiOleVirheita = false;
//            }
            if (tarkistaHavainnoijanumero(h.getHavainnoijaNumero()) == false) {
                System.out.println("Havainnoijanumero on virheellinen.");
                eiOleVirheita = false;
            }
        }

        if (tarkistaKunta(kunta) == false) {
            System.out.println(kunta + " ei ole validi kunnan lyhenne. Reittinro: " + tarkistettava.getReitinNumero());
            eiOleVirheita = false;
            onkoKuntaOikein = false;
        }

        if (onkoKuntaOikein == true && tarkistapeninkulmaruutu(kunta,
                tarkistettava.getPohjoiskoordinaatti(), tarkistettava.getItakoordinaatti()) == false) {
            //System.out.println("Kunta ja koordinaatit eivät matchaa!");
            eiOleVirheita = false;
        }
        if (tarkistaPisteidenLkm(tarkistettava.getPisteidenLkm()) == false) {
            //System.out.println("Pisteiden lukumäärä ei ole 20!");
            //eiOleVirheita = false;
        }
        if (tarkistaPistevuodenTapahtumat(tarkistettava) == false) {
            eiOleVirheita = false;
        }
        return eiOleVirheita;
    }

    private boolean tarkistaPistevuodenTapahtumat(Reitti tarkistettava) {
        boolean eiOleVirheita = true;
        for (Havaintopiste h : tarkistettava.getHavaintopisteet()) {
            for (Pistevuosi p : h.getPistevuodet()) {
                if (tarkistaSade(p.getReitinSade()) == false) {
                    System.out.println("Reitin säde on " + p.getReitinSade());
                    eiOleVirheita = false;
                }
                if (tarkistaBiotooppi(p.getBiotooppikoodiNyt()) == false) {
                    System.out.println("Biotooppikoodi on virheellinen. Piste: " + p.getPisteenJarjestysnumero() + "\nReitin numero: " + p.getReitinNumero() + ", biotooppi: " + p.getBiotooppikoodiNyt());
                    eiOleVirheita = false;
                }
                for (Parvihavainto l : p.getParvihavainnot()) {
                    if (tarkistaLintulaji(l.getParvilaji().trim()) == false) {
                        System.out.println("Parven laji on virheellinen Piste: " + p.getPisteenJarjestysnumero() + "\nReitin numero: " + p.getReitinNumero() + " Parven lyhenne: " + l.getParvilaji());
                        eiOleVirheita = false;
                    }
                    if (tarkistaParvenKoko(l.getParvenKoko()) == false) {
                        System.out.println("Parven koko on virheellinen. Piste: " + p.getPisteenJarjestysnumero() + "\nReitin numero: " + p.getReitinNumero() + ", parven koko: " + l.getParvenKoko() + " (" + l.getParvilaji() + ")");
                        eiOleVirheita = false;
                    }
                }
            }

        }
        return eiOleVirheita;
    }

    private boolean tarkistaSade(int sade) {
        if (sade == 50 || sade == 25) {
            return true;
        }
        return false;
    }

    private int[] teeLaskentaAika(int vuosi, int kuukausi, int paiva, int tunnit, int minuutit) {
        int[] taulukko = new int[5];
        taulukko[0] = vuosi;
        taulukko[1] = kuukausi;
        taulukko[2] = paiva;
        taulukko[3] = tunnit;
        taulukko[4] = minuutit;
        return taulukko;
    }

    private boolean tarkistaBiotooppi(int tarkistettava) {
        if (tarkistettava < 1 || tarkistettava > 17) {
            return false;
        }
        return true;
    }
}




